<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>Qt 4.3: document.cpp Example File (demos/undo/document.cpp)</title>
  <link href="classic.css" rel="stylesheet" type="text/css" />
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td align="left" valign="top" width="32"><a href="http://www.trolltech.com/products/qt"><img src="images/qt-logo.png" align="left" width="32" height="32" border="0" /></a></td>
<td width="1">&nbsp;&nbsp;</td><td class="postheader" valign="center"><a href="index.html"><font color="#004faf">Home</font></a>&nbsp;&middot; <a href="classes.html"><font color="#004faf">All&nbsp;Classes</font></a>&nbsp;&middot; <a href="mainclasses.html"><font color="#004faf">Main&nbsp;Classes</font></a>&nbsp;&middot; <a href="groups.html"><font color="#004faf">Grouped&nbsp;Classes</font></a>&nbsp;&middot; <a href="modules.html"><font color="#004faf">Modules</font></a>&nbsp;&middot; <a href="functions.html"><font color="#004faf">Functions</font></a></td>
<td align="right" valign="top" width="230"><a href="http://www.trolltech.com"><img src="images/trolltech-logo.png" align="right" width="203" height="32" border="0" /></a></td></tr></table><h1 align="center">document.cpp Example File<br /><sup><sup>demos/undo/document.cpp</sup></sup></h1>
<pre><span class="comment"> /****************************************************************************
 **
 ** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
 **
 ** This file is part of the documentation of the Qt Toolkit.
 **
 ** This file may be used under the terms of the GNU General Public
** License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file.  Alternatively you may (at
** your option) use any later version of the GNU General Public
** License if such license has been publicly approved by Trolltech ASA
** (or its successors, if any) and the KDE Free Qt Foundation. 
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://trolltech.com/products/qt/licenses/licensing/opensource/. If
** you are unsure which license is appropriate for your use, please
** review the following information:
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
** or contact the sales department at sales@trolltech.com.
**
** In addition, as a special exception, Trolltech, as the sole
** copyright holder for Qt Designer, grants users of the Qt/Eclipse
** Integration plug-in the right for the Qt/Eclipse Integration to
** link to functionality provided by Qt Designer and its related
** libraries.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. Trolltech reserves all rights not expressly
** granted herein.
 **
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 **
 ****************************************************************************/</span>

 #include &lt;math.h&gt;
 #include &lt;qevent.h&gt;
 #include &lt;QPainter&gt;
 #include &lt;QTextStream&gt;
 #include &lt;QUndoStack&gt;
 #include &quot;document.h&quot;
 #include &quot;commands.h&quot;

 static const int resizeHandleWidth = 6;

<span class="comment"> /******************************************************************************
 ** Shape
 */</span>

 const QSize Shape::minSize(80, 50);

 Shape::Shape(Type type, const QColor &amp;color, const QRect &amp;rect)
     : m_type(type), m_rect(rect), m_color(color)
 {
 }

 Shape::Type Shape::type() const
 {
     return m_type;
 }

 QRect Shape::rect() const
 {
     return m_rect;
 }

 QColor Shape::color() const
 {
     return m_color;
 }

 QString Shape::name() const
 {
     return m_name;
 }

 QRect Shape::resizeHandle() const
 {
     QPoint br = m_rect.bottomRight();
     return QRect(br - QPoint(resizeHandleWidth, resizeHandleWidth), br);
 }

 QString Shape::typeToString(Type type)
 {
     QString result;

     switch (type) {
         case Rectangle:
             result = QLatin1String(&quot;Rectangle&quot;);
             break;
         case Circle:
             result = QLatin1String(&quot;Circle&quot;);
             break;
         case Triangle:
             result = QLatin1String(&quot;Triangle&quot;);
             break;
     }

     return result;
 }

 Shape::Type Shape::stringToType(const QString &amp;s, bool *ok)
 {
     if (ok != 0)
         *ok = true;

     if (s == QLatin1String(&quot;Rectangle&quot;))
         return Rectangle;
     if (s == QLatin1String(&quot;Circle&quot;))
         return Circle;
     if (s == QLatin1String(&quot;Triangle&quot;))
         return Triangle;

     if (ok != 0)
         *ok = false;
     return Rectangle;
 }

<span class="comment"> /******************************************************************************
 ** Document
 */</span>

 Document::Document(QWidget *parent)
     : QWidget(parent), m_currentIndex(-1), m_mousePressIndex(-1), m_resizeHandlePressed(false)
 {
     m_undoStack = new QUndoStack(this);

     setAutoFillBackground(true);
     setBackgroundRole(QPalette::Base);

     QPalette pal = palette();
     pal.setBrush(QPalette::Base, QPixmap(&quot;:/icons/background.png&quot;));
     pal.setColor(QPalette::HighlightedText, Qt::red);
     setPalette(pal);
 }

 QString Document::addShape(const Shape &amp;shape)
 {
     QString name = Shape::typeToString(shape.type());
     name = uniqueName(name);

     m_shapeList.append(shape);
     m_shapeList[m_shapeList.count() - 1].m_name = name;
     setCurrentShape(m_shapeList.count() - 1);

     return name;
 }

 void Document::deleteShape(const QString &amp;shapeName)
 {
     int index = indexOf(shapeName);
     if (index == -1)
         return;

     update(m_shapeList.at(index).rect());

     m_shapeList.removeAt(index);

     if (index &lt;= m_currentIndex) {
         m_currentIndex = -1;
         if (index == m_shapeList.count())
             --index;
         setCurrentShape(index);
     }
 }

 Shape Document::shape(const QString &amp;shapeName) const
 {
     int index = indexOf(shapeName);
     if (index == -1)
         return Shape();
     return m_shapeList.at(index);
 }

 void Document::setShapeRect(const QString &amp;shapeName, const QRect &amp;rect)
 {
     int index = indexOf(shapeName);
     if (index == -1)
         return;

     Shape &amp;shape = m_shapeList[index];

     update(shape.rect());
     update(rect);

     shape.m_rect = rect;
 }

 void Document::setShapeColor(const QString &amp;shapeName, const QColor &amp;color)
 {

     int index = indexOf(shapeName);
     if (index == -1)
         return;

     Shape &amp;shape = m_shapeList[index];
     shape.m_color = color;

     update(shape.rect());
 }

 QUndoStack *Document::undoStack() const
 {
     return m_undoStack;
 }

 bool Document::load(QTextStream &amp;stream)
 {
     m_shapeList.clear();

     while (!stream.atEnd()) {
         QString shapeType, shapeName, colorName;
         int left, top, width, height;
         stream &gt;&gt; shapeType &gt;&gt; shapeName &gt;&gt; colorName &gt;&gt; left &gt;&gt; top &gt;&gt; width &gt;&gt; height;
         if (stream.status() != QTextStream::Ok)
             return false;
         bool ok;
         Shape::Type type = Shape::stringToType(shapeType, &amp;ok);
         if (!ok)
             return false;
         QColor color(colorName);
         if (!color.isValid())
             return false;

         Shape shape(type);
         shape.m_name = shapeName;
         shape.m_color = color;
         shape.m_rect = QRect(left, top, width, height);

         m_shapeList.append(shape);
     }

     m_currentIndex = m_shapeList.isEmpty() ? -1 : 0;

     return true;
 }

 void Document::save(QTextStream &amp;stream)
 {
     for (int i = 0; i &lt; m_shapeList.count(); ++i) {
         const Shape &amp;shape = m_shapeList.at(i);
         QRect r = shape.rect();
         stream &lt;&lt; Shape::typeToString(shape.type()) &lt;&lt; QLatin1Char(' ')
                 &lt;&lt; shape.name() &lt;&lt; QLatin1Char(' ')
                 &lt;&lt; shape.color().name() &lt;&lt; QLatin1Char(' ')
                 &lt;&lt; r.left() &lt;&lt; QLatin1Char(' ')
                 &lt;&lt; r.top() &lt;&lt; QLatin1Char(' ')
                 &lt;&lt; r.width() &lt;&lt; QLatin1Char(' ')
                 &lt;&lt; r.height();
         if (i != m_shapeList.count() - 1)
             stream &lt;&lt; QLatin1Char('\n');
     }
     m_undoStack-&gt;setClean();
 }

 QString Document::fileName() const
 {
     return m_fileName;
 }

 void Document::setFileName(const QString &amp;fileName)
 {
     m_fileName = fileName;
 }

 int Document::indexAt(const QPoint &amp;pos) const
 {
     for (int i = m_shapeList.count() - 1; i &gt;= 0; --i) {
         if (m_shapeList.at(i).rect().contains(pos))
             return i;
     }
     return -1;
 }

 void Document::mousePressEvent(QMouseEvent *event)
 {
     event-&gt;accept();
     int index = indexAt(event-&gt;pos());;
     if (index != -1) {
         setCurrentShape(index);

         const Shape &amp;shape = m_shapeList.at(index);
         m_resizeHandlePressed = shape.resizeHandle().contains(event-&gt;pos());

         if (m_resizeHandlePressed)
             m_mousePressOffset = shape.rect().bottomRight() - event-&gt;pos();
         else
             m_mousePressOffset = event-&gt;pos() - shape.rect().topLeft();
     }
     m_mousePressIndex = index;
 }

 void Document::mouseReleaseEvent(QMouseEvent *event)
 {
     event-&gt;accept();
     m_mousePressIndex = -1;
 }

 void Document::mouseMoveEvent(QMouseEvent *event)
 {
     event-&gt;accept();

     if (m_mousePressIndex == -1)
         return;

     const Shape &amp;shape = m_shapeList.at(m_mousePressIndex);

     QRect rect;
     if (m_resizeHandlePressed) {
         rect = QRect(shape.rect().topLeft(), event-&gt;pos() + m_mousePressOffset);
     } else {
         rect = shape.rect();
         rect.moveTopLeft(event-&gt;pos() - m_mousePressOffset);
     }

     QSize size = rect.size().expandedTo(Shape::minSize);
     rect.setSize(size);

     m_undoStack-&gt;push(new SetShapeRectCommand(this, shape.name(), rect));
 }

 static QGradient gradient(const QColor &amp;color, const QRect &amp;rect)
 {
     QColor c = color;
     c.setAlpha(160);
     QLinearGradient result(rect.topLeft(), rect.bottomRight());
     result.setColorAt(0, c.dark(150));
     result.setColorAt(0.5, c.light(200));
     result.setColorAt(1, c.dark(150));
     return result;
 }

 static QPolygon triangle(const QRect &amp;rect)
 {
     QPolygon result(3);
     result.setPoint(0, rect.center().x(), rect.top());
     result.setPoint(1, rect.right(), rect.bottom());
     result.setPoint(2, rect.left(), rect.bottom());
     return result;
 }

 void Document::paintEvent(QPaintEvent *event)
 {
     QRegion paintRegion = event-&gt;region();
     QPainter painter(this);
     QPalette pal = palette();

     for (int i = 0; i &lt; m_shapeList.count(); ++i) {
         const Shape &amp;shape = m_shapeList.at(i);

         if (!paintRegion.contains(shape.rect()))
             continue;

         QPen pen = pal.text().color();
         pen.setWidth(i == m_currentIndex ? 2 : 1);
         painter.setPen(pen);
         painter.setBrush(gradient(shape.color(), shape.rect()));

         QRect rect = shape.rect();
         rect.adjust(1, 1, -resizeHandleWidth/2, -resizeHandleWidth/2);

         <span class="comment">//</span> paint the shape
         switch (shape.type()) {
             case Shape::Rectangle:
                 painter.drawRect(rect);
                 break;
             case Shape::Circle:
                 painter.setRenderHint(QPainter::Antialiasing);
                 painter.drawEllipse(rect);
                 painter.setRenderHint(QPainter::Antialiasing, false);
                 break;
             case Shape::Triangle:
                 painter.setRenderHint(QPainter::Antialiasing);
                 painter.drawPolygon(triangle(rect));
                 painter.setRenderHint(QPainter::Antialiasing, false);
                 break;
         }

         <span class="comment">//</span> paint the resize handle
         painter.setPen(pal.text().color());
         painter.setBrush(Qt::white);
         painter.drawRect(shape.resizeHandle().adjusted(0, 0, -1, -1));

         <span class="comment">//</span> paint the shape name
         painter.setBrush(pal.text());
         if (shape.type() == Shape::Triangle)
             rect.adjust(0, rect.height()/2, 0, 0);
         painter.drawText(rect, Qt::AlignCenter, shape.name());
     }
 }

 void Document::setCurrentShape(int index)
 {
     QString currentName;

     if (m_currentIndex != -1)
         update(m_shapeList.at(m_currentIndex).rect());

     m_currentIndex = index;

     if (m_currentIndex != -1) {
         const Shape &amp;current = m_shapeList.at(m_currentIndex);
         update(current.rect());
         currentName = current.name();
     }

     emit currentShapeChanged(currentName);
 }

 int Document::indexOf(const QString &amp;shapeName) const
 {
     for (int i = 0; i &lt; m_shapeList.count(); ++i) {
         if (m_shapeList.at(i).name() == shapeName)
             return i;
     }
     return -1;
 }

 QString Document::uniqueName(const QString &amp;name) const
 {
     QString unique;

     for (int i = 0; ; ++i) {
         unique = name;
         if (i &gt; 0)
             unique += QString::number(i);
         if (indexOf(unique) == -1)
             break;
     }

     return unique;
 }

 QString Document::currentShapeName() const
 {
     if (m_currentIndex == -1)
         return QString();
     return m_shapeList.at(m_currentIndex).name();
 }</pre>
<p /><address><hr /><div align="center">
<table width="100%" cellspacing="0" border="0"><tr class="address">
<td width="30%">Copyright &copy; 2008 <a href="trolltech.html">Trolltech</a></td>
<td width="40%" align="center"><a href="trademarks.html">Trademarks</a></td>
<td width="30%" align="right"><div align="right">Qt 4.3.5</div></td>
</tr></table></div></address></body>
</html>
